﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ResourceBlender.Core;

namespace ResourceBlender.DAL.Import
{
    public class PropertiesResourceImporter : ResourceImporterBase
    {
        private static Regex rx = new Regex(@"\\[uU]([0-9a-f]{4})", RegexOptions.IgnoreCase);

        /// <summary>
        /// Imports elements and resources from existing .properties bundles, then prompts for an application to which to import.
        /// </summary>
        /// <param name="log">A delegate to which log message should be sent.</param>
        /// <param name="files">The files to import.</param>
        /// <param name="application">The application into which to import the bundles.</param>
        /// <param name="appendLanguages"><c>true</c> if languages not currently used by the application should be added, otherwise false.</param>
        /// <param name="nameFilter">If not <c>null</c>, only elements whose name conatins this string will be imported.</param>
        public static void Import(StatusMessage.StatusChangedEventHandler log, Dictionary<string, string> files, RBApplication application, bool appendLanguages, string nameFilter)
        {
            Dictionary<string, Dictionary<string, RBElement>> bundles = new Dictionary<string, Dictionary<string, RBElement>>(); // <bundle, <elementname, elementData>>
            string bundleName, language, elementName;
            int splitter, elementSplitter;
            Dictionary<string, RBElement> currentBundle;
            log(new StatusMessage(I18nUtils.GetString("UIStrings", "ParsingBundles"), StatusMessage.StatusMessageType.Status));
            List<string> newLanguages = new List<string>();
            foreach (KeyValuePair<string, string> file in files)
            { // <filename, UTF8 contents>
                string fileNameNoExt = Path.GetFileNameWithoutExtension(file.Key);
                splitter = fileNameNoExt.IndexOf('_');
                if (splitter <= 0)
                {
                    continue;
                }
                bundleName = fileNameNoExt.Substring(0, splitter);
                language = Utils.JavaCulture2DotNetCulture(fileNameNoExt.Substring(splitter + 1));
                if (appendLanguages && !application.Languages.Contains(language) && !newLanguages.Contains(language))
                {
                    newLanguages.Add(language);
                }
                if (bundles.ContainsKey(bundleName))
                {
                    currentBundle = bundles[bundleName];
                }
                else
                {
                    currentBundle = new Dictionary<string, RBElement>();
                    bundles.Add(bundleName, currentBundle);
                }
                string[] elements = file.Value.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string totalElement in elements)
                {
                    try
                    {
                        elementSplitter = totalElement.IndexOf('=');
                        elementName = totalElement.Substring(0, elementSplitter);
                        if (nameFilter != null && !elementName.Contains(nameFilter))
                        {
                            log(new StatusMessage(string.Format("Element '{0}' excluded by filter, skipping...", elementName), StatusMessage.StatusMessageType.Status));
                            continue;
                        }
                        RBTranslation trans = new RBTranslation(language, rx.Replace(totalElement.Substring(elementSplitter + 1), match => ((char)Int32.Parse(match.Value.Substring(2), NumberStyles.HexNumber)).ToString()).TrimEnd('\r'), string.Empty);
                        if (currentBundle.ContainsKey(elementName))
                        {
                            currentBundle[elementName].Resource.Translations.Add(language, trans);
                        }
                        else
                        {
                            RBElement element = new RBElement();
                            element.Resource.Translations.Add(language, trans);
                            currentBundle.Add(elementName, element);
                        }
                    }
                    catch (Exception ex)
                    {
                        log(new StatusMessage(string.Format(I18nUtils.GetString("Errors", "ErrorParsingDesc"), totalElement, ex.Message), StatusMessage.StatusMessageType.Error));
                    }
                }
            }
            ProcessBundles(bundles, application, log);
            if (newLanguages.Count > 0)
            {
                Database db = null;
                try
                {
                    db = new Database();
                    db.OpenConnection();
                    using (Command cmd = db.CreateCommand())
                    {
                        application.Languages.AddRange(newLanguages);
                        cmd.CommandText = string.Format("UPDATE {0}applications SET languages = @langs WHERE id = @applicationId", db.TablePrefix);
                        cmd.AddParameterWithValue("@langs", Utils.Implode(application.Languages, ",", true));
                        cmd.AddParameterWithValue("@applicationId", application.ID);
                        cmd.ExecuteNonQuery();
                        log(new StatusMessage(string.Format(I18nUtils.GetString("UIStrings", "AddedNumNewLanguages"), newLanguages.Count), StatusMessage.StatusMessageType.Success));//UIStrings.AddedNumNewLanguages
                    }
                }
                catch (Exception ex)
                {
                    log(new StatusMessage(ex.Message, StatusMessage.StatusMessageType.Error));
                }
                finally
                {
                    if (db != null && db.Connected)
                    {
                        try
                        {
                            db.CloseConnection();
                        }
                        catch { }
                    }
                }
            }
        }
  
    }
}
